/* 
    This file is part of eJourn.

    eJourn is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    eJourn is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with eJourn; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */
#include "list.h"
#include "dict.h"
#include <string.h>

lstiter *list_start_iter(struct list *lst) {	return lst->items;	}

lstiter *list_iter_next(lstiter *iter)
{
	if (iter)
		return iter->next;
	return NULL;
}
void *list_iter_get(lstiter *iter)
{
	if (iter)
		return iter->value;
	return NULL;
}
int list_iter_get_type(lstiter *iter)
{
	if (iter)
		return iter->type;
	return -1;	
}


struct list *list_from_dict(struct dict *d)
{
	struct list *ret = list_new();
	list_add(ret, d->root->value);
	list_type(ret, d->root->type);
	list_free_able(ret, 0); //the dict owns it.	
	return ret;
}

struct list *list_new()
{
  struct list *l = malloc(sizeof *l);
  l->items = NULL;
  l->ref = 1;
  l->size = 0;
  return l;
}

void list_add(struct list *l, void *val)
{
  struct list_item *n = malloc(sizeof *n);
  n->value = val;
  n->next = l->items;
  n->free = 0;
  n->type = 1;
  l->items = n;
  l->size += 1;
}
int list_size(struct list *l)
{
	return l->size;
}

void list_rm(struct list *l, void *val)
{
  struct list_item *p = l->items;
  if (!p)
	return;
  while (p->next) {
	if (p->next->value == val) {
	  struct list_item *q = p->next;
	  p->next = p->next->next;
	  if (q->free) {
	  	if (q->type == DICT_TYPE_DCT)
			dict_unref(q->value);
		else if (q->type == DICT_TYPE_LST)
			list_unref(q->value);
		else
			free(q->value);
	  }
	  free(q);
	}
	p=p->next;
  }
  l->size -= 1;
}

void list_free_able(struct list *l, int free)
{
  if (l->items)
	l->items->free = free;
}

void list_type(struct list *l, int type)
{
  if (l->items) {
	l->items->type = type;
	if (type == DICT_TYPE_LST)
		list_ref(l->items->value);
	else if (type == DICT_TYPE_DCT)
		dict_ref(l->items->value);
  }
}

void list_free(struct list *l)
{
  struct list_item *p = l->items;
  while (p) {
	struct list_item *q = p;
	p=p->next;
	if (q->free) {
		if (q->type == DICT_TYPE_LST)
			list_unref(q->value);
		else if (q->type == DICT_TYPE_DCT)
			dict_unref(q->value);
		else
			free(q->value);
	}
	free(q);
  }
  free(l);
}
void list_print(struct list *l)
{
	struct list_item *q = l->items;
	while (q) {
		switch (q->type) {
			case DICT_TYPE_INT: 
				printf("Integer:%i\n", *(int *)(q->value));
				break;	
			case DICT_TYPE_LST:
				printf("Recursing to new list:\n");
				list_print((struct list *)(q->value));
				break;
			case DICT_TYPE_DCT:
				printf("Recursing into dict:\n");
				dict_print((struct dict *)(q->value));
				break;
			case DICT_TYPE_OBJ:
				break; //can't do anything here..
				
			case DICT_TYPE_STR:
				printf("String:%s\n", (char *)(q->value));
				break;
		}
		q = q->next;	
	}	
}

void list_ref(struct list *l)
{
	l->ref += 1;	
}
void list_unref(struct list *l)
{
	l->ref -= 1;
	if (l->ref <= 0) {
		list_free(l);	
	}	
}

#ifdef TEST
int main(void)
{
	struct list *lst = list_new("my list");
	list_add(lst, "hello world");
	list_type(lst, DICT_TYPE_STR);
	
	int *n = malloc(sizeof *n);
	*n = 15;
	list_add(lst, n);
	list_type(lst, DICT_TYPE_INT);
	list_free_able(lst, 1);
	
	struct list *lst2 = list_new("Inside list");
	list_add(lst, lst2);
	list_type(lst, DICT_TYPE_LST);
	list_free_able(lst, 1);
	
	list_add(lst2, "some more junk");
	list_type(lst2, DICT_TYPE_STR);

	printf("---\n");	
	list_print(lst);
	list_free(lst);
	
	printf("---\n\nDoes it look like the following?\n\n---\n");
	printf("%s\n%s\n%s\n%s\n%s\n", "Name:my list",
									"Recursing to new list:Name:Inside list",
									"String:some more junk",
									"Integer:15",
									"String:hello world");
	printf("---\n");
	
	return 0;	
}

#endif

